package jclass

import (
	"encoding/binary"
	"fmt"
	"io"
	"os"
)

// WriteClassFile 将修改后的类文件数据写入文件。
func WriteClassFile(classFile *ClassFile, filename string) error {
	file, err := os.Create(filename)
	if err != nil {
		return err
	}
	defer file.Close()

	// 写入魔数、次版本号和主版本号
	err = binary.Write(file, binary.BigEndian, classFile.Magic)
	if err != nil {
		return err
	}
	err = binary.Write(file, binary.BigEndian, classFile.MinorVersion)
	if err != nil {
		return err
	}
	err = binary.Write(file, binary.BigEndian, classFile.MajorVersion)
	if err != nil {
		return err
	}

	// 写入常量池的数量和项目
	err = binary.Write(file, binary.BigEndian, uint16(len(classFile.ConstantPool.Info)+1)) // +1 是因为常量池的计数从 1 开始
	if err != nil {
		return err
	}
	for _, item := range classFile.ConstantPool.Info {
		// 你需要实现每个常量池项目的序列化逻辑
		if item == nil {
			continue
		}
		err = writeConstantPoolItem(file, *item)
		if err != nil {
			return err
		}
	}

	// 写入访问标志、这个类和超类的索引
	err = binary.Write(file, binary.BigEndian, classFile.AccessFlags)
	if err != nil {
		return err
	}
	err = binary.Write(file, binary.BigEndian, classFile.ThisClass)
	if err != nil {
		return err
	}
	err = binary.Write(file, binary.BigEndian, classFile.SuperClass)
	if err != nil {
		return err
	}

	// 写入接口的数量和索引
	err = binary.Write(file, binary.BigEndian, uint16(len(classFile.Interfaces)))
	if err != nil {
		return err
	}
	for _, index := range classFile.Interfaces {
		err = binary.Write(file, binary.BigEndian, index)
		if err != nil {
			return err
		}
	}

	// 写入字段的数量和字段信息
	err = binary.Write(file, binary.BigEndian, uint16(len(classFile.Fields)))
	if err != nil {
		return err
	}
	for _, field := range classFile.Fields {
		// 你需要实现每个字段信息的序列化逻辑
		err = writeFieldInfo(file, *field)
		if err != nil {
			return err
		}
	}
	// 写入方法的数量和方法信息
	err = binary.Write(file, binary.BigEndian, uint16(len(classFile.Methods)))
	if err != nil {
		return err
	}
	for _, method := range classFile.Methods {
		// 你需要实现每个方法信息的序列化逻辑
		err = writeMethodInfo(file, *method)
		if err != nil {
			return err
		}
	}

	// 写入属性的数量和属性信息
	err = binary.Write(file, binary.BigEndian, uint16(len(classFile.Attributes)))
	if err != nil {
		return err
	}
	for _, attribute := range classFile.Attributes {
		// 你需要实现每个属性信息的序列化逻辑
		err = writeAttributeInfo(file, *attribute)
		if err != nil {
			return err
		}
	}

	return nil
}

// writeConstantPoolItem 将常量池项目序列化到文件。
func writeConstantPoolItem(w io.Writer, item CpInfo) error {
	// 根据 Tag 字段的值实现每种常量池项目的序列化逻辑
	err := binary.Write(w, binary.BigEndian, U1(item.Tag))
	if err != nil {
		return err
	}
	fmt.Println("Tag", item)
	// 根据 Tag 的不同，可能还需要序列化其他字段...
	switch item.Tag {
	case Class:
		// item.NameIndex = ReadU2(r)
		err := binary.Write(w, binary.BigEndian, item.NameIndex)
		if err != nil {
			return err
		}
	case FieldRef, MethodRef, InterfaceMethodRef:
		// item.ClassIndex = ReadU2(r)
		// item.NameAndTypeIndex = ReadU2(r)
		err := binary.Write(w, binary.BigEndian, item.ClassIndex)
		if err != nil {
			return err
		}
		{
			err := binary.Write(w, binary.BigEndian, item.NameAndTypeIndex)
			if err != nil {
				return err
			}
		}
	case String:
		// item.StringIndex = ReadU2(r)
		err := binary.Write(w, binary.BigEndian, item.StringIndex)
		if err != nil {
			return err
		}
	case Integer, Float:
		// item.Bytes = ReadU4(r)
		err := binary.Write(w, binary.BigEndian, item.Bytes)
		if err != nil {
			return err
		}
	case Long, Double:
		// item.HighBytes = ReadU4(r)
		// item.LowBytes = ReadU4(r)
		err := binary.Write(w, binary.BigEndian, item.HighBytes)
		if err != nil {
			return err
		}
		{
			err := binary.Write(w, binary.BigEndian, item.LowBytes)
			if err != nil {
				return err
			}
		}
	case NameAndType:
		// item.NameIndex = ReadU2(r)
		// item.DescriptorIndex = ReadU2(r)
		err := binary.Write(w, binary.BigEndian, item.NameIndex)
		if err != nil {
			return err
		}
		{
			err := binary.Write(w, binary.BigEndian, item.DescriptorIndex)
			if err != nil {
				return err
			}
		}
	case Utf8:
		// item.Length = ReadU2(r)
		// item.readUtf8Bytes(r)
		err := binary.Write(w, binary.BigEndian, item.Length)
		if err != nil {
			return err
		}

		// b interface{} = &item.Uinerr
		w.Write([]byte(item.Utf8Str))
	case MethodHandle:
		// item.ReferenceKind = ReadU1(r)
		// item.ReferenceIndex = ReadU2(r)
		err := binary.Write(w, binary.BigEndian, item.ReferenceKind)
		if err != nil {
			return err
		}
		{
			err := binary.Write(w, binary.BigEndian, item.ReferenceIndex)
			if err != nil {
				return err
			}
		}
	case MethodType:
		// item.DescriptorIndex = ReadU2(r)
		err := binary.Write(w, binary.BigEndian, item.DescriptorIndex)
		if err != nil {
			return err
		}
	case InvokeDynamic:
		// item.BootstrapMethodAttrIndex = ReadU2(r)
		// item.NameAndTypeIndex = ReadU2(r)
		err := binary.Write(w, binary.BigEndian, item.BootstrapMethodAttrIndex)
		if err != nil {
			return err
		}
		{
			err := binary.Write(w, binary.BigEndian, item.NameAndTypeIndex)
			if err != nil {
				return err
			}
		}
	}

	return nil
}

// writeFieldInfo 将字段信息序列化到文件。
func writeFieldInfo(w io.Writer, field FieldInfo) error {
	// 实现字段信息的序列化逻辑
	err := binary.Write(w, binary.BigEndian, field.AccessFlags)
	if err != nil {
		return err
	}
	err = binary.Write(w, binary.BigEndian, field.NameIndex)
	if err != nil {
		return err
	}
	err = binary.Write(w, binary.BigEndian, field.DescriptorIndex)
	if err != nil {
		return err
	}
	writeNumbers(w, field.AttributesCount)
	for _, v := range field.Attributes {
		writeAttributeInfo(w, *v)
	}

	// 序列化属性数量和属性信息...
	return nil
}

// writeMethodInfo 将方法信息序列化到文件。
func writeMethodInfo(w io.Writer, method MethodInfo) error {
	// 实现方法信息的序列化逻辑
	err := binary.Write(w, binary.BigEndian, method.AccessFlags)
	if err != nil {
		return err
	}
	err = binary.Write(w, binary.BigEndian, method.NameIndex)
	if err != nil {
		return err
	}
	err = binary.Write(w, binary.BigEndian, method.DescriptorIndex)
	if err != nil {
		return err
	}

	err = binary.Write(w, binary.BigEndian, method.AttributesCount)
	if err != nil {
		return err
	}
	for _, attribute := range method.Attributes {
		// if attribute.Code != nil {
		// 	continue
		// }
		err = writeAttributeInfo(w, *attribute)
		if err != nil {
			return err
		}
	}
	// 序列化属性数量和属性信息...
	return nil
}

// writeAttributeInfo 将属性信息序列化到文件。
func writeAttributeInfo(w io.Writer, attribute AttributeInfo) error {
	// 实现属性信息的序列化逻辑
	err := binary.Write(w, binary.BigEndian, attribute.NameIndex) //attribute.AttributeNameIndex)
	if err != nil {
		return err
	}
	err = binary.Write(w, binary.BigEndian, attribute.Length)
	if err != nil {
		return err
	}
	switch v := pool.At(attribute.NameIndex).Utf8(); AttributeName(v) {
	case ConstantValue:

		err := binary.Write(w, binary.BigEndian, attribute.ConstantValueIndex) //attribute.AttributeNameIndex)
		if err != nil {
			return err
		}
	case Code:
		attribute.writeCode(w)
		break
	case StackMapTable:
		attribute.writeStackMapTable(w)
		break
	case Exceptions:
		attribute.writeExceptions(w)
		break
	case BootstrapMethods:
		attribute.writeBootstrapMethods(w)
		break
	default:
		attribute.writeDefault(w)
		break
	}
	// _, err = w.Write(b.([]byte)) //attribute.AttributeInfo)
	// _, err = w.Write(append([]U1{}, attribute.Info...)) //attribute.AttributeInfo)

	if err != nil {
		return err
	}
	return nil
}

func writeNumbers[T any](w io.Writer, v T) error {
	err := binary.Write(w, binary.BigEndian, v) //attribute.AttributeNameIndex)
	if err != nil {
		return err
	}
	return nil
}
